import 'package:family_expense/features/bank_card/widgets/bank_shared.dart';
import 'package:family_expense/features/income_expense/constants/income_expense_type.dart';
import 'package:family_expense/features/income_expense/widgets/income_expense_detail_shared.dart';
import 'package:family_expense/features/journey/models/journey.dart';
import 'package:family_expense/features/journey/models/journey_income_expense_detail.dart';
import 'package:family_expense/features/journey/services/journey_income_expense_detail_service.dart';
import 'package:family_expense/features/journey/widgets/edit_journey_income_expense_detail.dart';
import 'package:family_expense/shared/widgets/action_log.dart';
import 'package:flutter/material.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:my_flutter_baidu_map/my_flutter_baidu_map.dart';
import 'package:my_flutter_core/my_flutter_core.dart';

class JourneyIncomeExpenseDetailViewArguments {
  const JourneyIncomeExpenseDetailViewArguments({
    required this.id,
    required this.journey,
  });

  final String id;
  final Journey journey;
}

/// The widget displays the details of the income/expense.
///
/// The data items are linked. For example, if you change the payment type from cash to credit card that would affect the bank card info.
/// That's why we are not using one-tap-to-change mode in this view. [BankCardInfo] is the sample of one-tap=to-change mode.
class JourneyIncomeExpenseDetailView extends StatefulWidget {
  const JourneyIncomeExpenseDetailView({
    super.key,
    required this.id,
    required this.journey,
  });

  final String id;
  final Journey journey;

  @override
  State<JourneyIncomeExpenseDetailView> createState() =>
      _JourneyIncomeExpenseDetailViewState();
}

class _JourneyIncomeExpenseDetailViewState
    extends State<JourneyIncomeExpenseDetailView> {
  static const Color _captionColor = Colors.black54;

  final double _buttomIconSize = 18.0;

  // Retrieves income/expense detail.
  final JourneyIncomeExpenseDetailService _incomeExpenseDetailService =
      JourneyIncomeExpenseDetailService();

  // Retrieved income/expense detail.
  JourneyIncomeExpenseDetail? _incomeExpenseDetail;

  // Used to notify last view that current item has been updated.
  bool _dataUpdated = false;

  @override
  void initState() {
    super.initState();

    _queryDetails();
  }

  @override
  Widget build(BuildContext context) {
    return PopScope(
      canPop: false,
      onPopInvokedWithResult: _onPopInvokedWithResult,
      child: Scaffold(appBar: _buildAppBar(), body: _buildBody()),
    );
  }

  /// Builds app bar.
  PreferredSizeWidget _buildAppBar() {
    return AppBar(title: const Text('收支详情'));
  }

  /// Builds the list view to display the details.
  Widget _buildBody() {
    if (_incomeExpenseDetail == null) {
      return const MyPageTopCenterLoadingIndicator();
    }

    return FutureBuilder<User?>(
      future: AuthStateService.instance.currentUser,
      builder: (context, userSnapshot) => ListView(
        padding: const EdgeInsets.all(4.0),
        children: [
          Card(
            elevation: 6.0,
            child: Padding(
              padding: const EdgeInsets.all(10.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(
                    children: [
                      Text(
                        _incomeExpenseDetail!.incomeExpenseDate!
                            .convertDateToFriendlyText(DatePatterns.longDate),
                        style: Theme.of(
                          context,
                        ).textTheme.titleSmall!.copyWith(color: _captionColor),
                      ),
                      Expanded(
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.end,
                          children: [
                            if (_incomeExpenseDetail!
                                    .bankCard
                                    ?.id
                                    .isNotNullOrEmpty ==
                                true)
                              BankLogo(_incomeExpenseDetail!.bankCard!.bank!),
                            const SizedBox(width: 6.0),
                            Text(
                              _incomeExpenseDetail!.bankCard?.name ?? '',
                              style: const TextStyle(color: _captionColor),
                            ),
                            Text(
                              ' (${IncomeExpenseDetailShared.getPaymentTypeTitle(_incomeExpenseDetail!.paymentType)})',
                              style: const TextStyle(color: _captionColor),
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 30.0),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          AmountSymbol(
                            _incomeExpenseDetail!.amount!,
                            color: _incomeExpenseDetail!.amount! >= 0
                                ? Colors.black54
                                : IncomeExpenseDetailShared.expenseAmountColor,
                          ),
                          const SizedBox(width: 2.0),
                          Text(
                            formatNumber(_incomeExpenseDetail!.amount!.abs()),
                            style: _incomeExpenseDetail!.amount! >= 0
                                ? Theme.of(context).textTheme.displaySmall
                                : Theme.of(
                                    context,
                                  ).textTheme.headlineMedium!.copyWith(
                                    color: IncomeExpenseDetailShared
                                        .expenseAmountColor,
                                  ),
                          ),
                        ],
                      ),
                      const SizedBox(width: 6.0),
                      Container(
                        margin: const EdgeInsets.only(bottom: 8.0),
                        child: Text(
                          _incomeExpenseDetail!.currency!,
                          style: Theme.of(context).textTheme.bodySmall,
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 30.0),
                  Text(
                    _incomeExpenseDetail!.details!,
                    style: const TextStyle(fontSize: 20.0),
                  ),
                  const SizedBox(height: 8.0),
                  Text(
                    _incomeExpenseDetail!.location!,
                    style: Theme.of(context).textTheme.bodySmall,
                  ),
                  const SizedBox(height: 30.0),
                  if (_incomeExpenseDetail!.remark.isNotNullOrEmpty)
                    ExpansionTile(
                      title: const Text('备注'),
                      children: [
                        ListTile(
                          title: Text(_incomeExpenseDetail!.remark ?? ''),
                        ),
                      ],
                    ),
                  if (_incomeExpenseDetail?.formattedAddress.isNotNullOrEmpty ==
                      true)
                    _buildLocation(),
                  const Divider(),
                  ActionLogView(_incomeExpenseDetail!),
                  const Divider(),
                  const SizedBox(height: 60.0),
                  if (userSnapshot.data?.isViewerOnly == false)
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: [
                        IconButtonWithBottomLabel(
                          icon: Icon(Icons.delete, size: _buttomIconSize),
                          label: Text(
                            '删除',
                            style: Theme.of(context).textTheme.bodySmall,
                          ),
                          onPressed: _incomeExpenseDetail != null
                              ? _delete
                              : null,
                        ),
                        IconButtonWithBottomLabel(
                          icon: Icon(
                            MdiIcons.contentCopy,
                            size: _buttomIconSize,
                          ),
                          label: Text(
                            '复制',
                            style: Theme.of(context).textTheme.bodySmall,
                          ),
                          onPressed: _incomeExpenseDetail != null
                              ? _gotoAddingViewWithClone
                              : null,
                        ),
                        IconButtonWithBottomLabel(
                          icon: Icon(
                            MdiIcons.squareEditOutline,
                            size: _buttomIconSize,
                          ),
                          label: Text(
                            '修改',
                            style: Theme.of(context).textTheme.bodySmall,
                          ),
                          onPressed: _incomeExpenseDetail != null
                              ? _gotoUpdateView
                              : null,
                        ),
                        if (_incomeExpenseDetail!.type ==
                            IncomeExpenseType.expense)
                          IconButtonWithBottomLabel(
                            icon: Icon(
                              MdiIcons.creditCard,
                              size: _buttomIconSize,
                            ),
                            label: Text(
                              '退款',
                              style: Theme.of(context).textTheme.bodySmall,
                            ),
                            onPressed: _incomeExpenseDetail != null
                                ? _gotoAddingViewWithRefundInfo
                                : null,
                          ),
                      ],
                    ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildLocation() {
    return Column(
      children: [
        const Divider(),
        ListTile(
          leading: const Icon(Icons.location_on, color: Color(0xFF00C161)),
          title: Text(
            _incomeExpenseDetail!.formattedAddress!,
            style: const TextStyle(fontSize: 14.0),
          ),
          onTap: () {
            NavigatorHelper.push<MapLocation>(
              context,
              MapLocationSelector(
                MapLocation(
                  latitude: _incomeExpenseDetail!.latitude,
                  longitude: _incomeExpenseDetail!.longitude,
                  province: _incomeExpenseDetail!.province,
                  city: _incomeExpenseDetail!.city,
                  address: _incomeExpenseDetail!.address,
                  formattedAddress: _incomeExpenseDetail!.formattedAddress,
                ),
              ),
            );
          },
        ),
      ],
    );
  }

  Future<void> _queryDetails() async {
    final res = await _incomeExpenseDetailService.queryDetails(widget.id);

    if (mounted) {
      setState(() => _incomeExpenseDetail = res);
    }
  }

  /// Deletes current detail.
  void _delete() {
    showConfirmDialog(
      context,
      '删除该记录？',
      onConfirm: () async {
        showInProgressOverlay(context);

        // Deletes item on back server.
        final success = await _incomeExpenseDetailService.delete(
          _incomeExpenseDetail!.id,
        );

        // DO NOT use BuildContext across asynchronous gaps.
        // https://dart-lang.github.io/linter/lints/use_build_context_synchronously.html
        if (mounted) {
          // Closes progress overlay.
          NavigatorHelper.pop(context);
        }

        // DO NOT use BuildContext across asynchronous gaps.
        // https://dart-lang.github.io/linter/lints/use_build_context_synchronously.html
        if (success && mounted) {
          // Pops detail view and notifies last page to reload.
          NavigatorHelper.pop(context, true);
        }
      },
    );
  }

  /// Goes to detail update view.
  Future<void> _gotoUpdateView() async {
    _incomeExpenseDetail!.journey = widget.journey;

    // Takes current result that if the data has been updated.
    final dataUpdated = await NavigatorHelper.push<bool>(
      context,
      EditJourneyIncomeExpenseDetail(incomeExpenseDetail: _incomeExpenseDetail),
    );

    // If [_dataUpdated] is true that means the data already has been updated.
    // Even user goes to the edit view and pops again without any change.
    // That's why we only need to change [_dataUpdated] value when it is false.
    //
    // Example:
    // 1. Goes to edit view, makes change and pops. Edit view returns true.
    // 2. Goes to edit view again, makes NO change and pops. Edit view returns false.
    // 3. We need to pass true to parent view anyway.
    if (!_dataUpdated) {
      _dataUpdated = dataUpdated!;
    }

    // Only when current result indicates the data has been changed then we need to refresh the data.
    if (dataUpdated == true) {
      // This action for display the loading icon.
      if (mounted) {
        setState(() => _incomeExpenseDetail = null);
      }

      // The action log wouldn't be updated if we take the updated [IncomeExpenseDetail]
      // from [EditIncomeExpense] view as return value.
      // That's why we need to retrieve the data again from server.
      final res = await _incomeExpenseDetailService.queryDetails(widget.id);

      if (mounted) {
        setState(() => _incomeExpenseDetail = res);
      }
    }
  }

  /// Goes to editing view with cloned data.
  /// This is used to clone an item with same details for quick editing.
  Future<void> _gotoAddingViewWithClone() async {
    // Clones current income/expense detail.
    final cloned = _incomeExpenseDetail!.clone();

    // Clears its id to make it as a new item.
    cloned.id = null;

    // For checking incomeExpenseDate is during journey date range.
    cloned.journey = widget.journey;

    // Goes to editing view with cloned data.
    final dataUpdated = await NavigatorHelper.push<bool>(
      context,
      EditJourneyIncomeExpenseDetail(incomeExpenseDetail: cloned),
    );

    // If data updated then pops current view and notifies last page to refresh.
    if (dataUpdated == true && mounted) {
      NavigatorHelper.pop(context, dataUpdated);
    }
  }

  /// Goes to editing view with cloned data.
  /// This is used to clone an item with same details for quick editing.
  Future<void> _gotoAddingViewWithRefundInfo() async {
    // Clones current income/expense detail.
    final cloned = _incomeExpenseDetail!.clone();

    // Clears its id to make it as a new item.
    cloned.id = null;

    // For checking incomeExpenseDate is during journey date range.
    cloned.journey = widget.journey;

    // Clears its amount.
    cloned.amount = null;

    // Sets refund to income.
    cloned.type = IncomeExpenseType.income;

    // Sets details with original info.
    cloned.details =
        '${_incomeExpenseDetail!.incomeExpenseDate.formatDate(DatePatterns.longLiteralDate)}${_incomeExpenseDetail!.details}${formatNumber(_incomeExpenseDetail!.amount!.abs())}元订单退款';

    // Goes to editing view with cloned data.
    final dataUpdated = await NavigatorHelper.push<bool>(
      context,
      EditJourneyIncomeExpenseDetail(incomeExpenseDetail: cloned),
    );

    // If data updated then pops current view and notifies last page to refresh.
    if (dataUpdated == true && mounted) {
      NavigatorHelper.pop(context, dataUpdated);
    }
  }

  void _onPopInvokedWithResult(bool didPop, dynamic result) {
    if (didPop) {
      return;
    }

    NavigatorHelper.pop(context, _dataUpdated);
  }
}
